﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using TeamDev.SDK;
using System.Runtime.Remoting;

namespace TDB.Services
{
  internal class Journaling
  {
    private static AppDomain _journalingAppDomain = null;

    private object filelock = new object();
    private FileStream _logfile = null;
    private BinaryWriter _writer = null;

    public string LogFileName { get; set; }
    public string DataBaseName { get; set; }

    public bool LogCommand(Guid id, byte[] data)
    {
      if (Configuration.Current.Journaling == JournalingMode.Off) return true;
      lock (filelock)
      {
        if (OpenLogFile())
        {
          // Writing the journal
          _writer.Write('K');
          _writer.Write(DateTime.Now.ToOADate());
          _writer.Write((int)JournalingCommandsEnum.SetObject);
          _writer.Write(id.ToByteArray());
          _writer.Write('D');
          _writer.Write(data.Length);
          _writer.Write(data);

          return EnsureWrite();
        }
      }
      return false;
    }

    public bool Init()
    {
      // Journaling Default Parameters. 
      LogFileName = Configuration.Current.DataBasePath;
      LogFileName = Path.Combine(LogFileName, DataBaseName);

      try
      {
        if (!Directory.Exists(LogFileName))
        {
          Directory.CreateDirectory(LogFileName);
        }
      }
      catch (Exception ex)
      {
        EventLogWriter.LogException(ex);
        Server.EmergencyShutdown();
        return false;
      }

      LogFileName = Path.Combine(LogFileName, "TDB.Journal");
      return OpenLogFile();
    }

    public static bool InitJournaling()
    {
      //foreach (var sn in Server.GetStores())
      //{
      //  var store = Server.GetStore(sn);
      //  if (!store.Journaling.Init())
      //    return false;
      //}
      return true;
    }

    public static void StopJournaling()
    {
      //foreach (var sn in Server.GetStores())
      //{
      //  var store = Server.GetStore(sn);
      //  store.Journaling.CloseFile();
      //}
    }

    public void CloseFile()
    {
      lock (filelock)
      {
        if (_logfile != null)
        {
          EnsureWrite();
          _logfile.Flush(true);
          _logfile.Close();
        }
      }
    }

    private bool EnsureWrite()
    {
      try
      {
        _logfile.Flush(Configuration.Current.Journaling == JournalingMode.Secure);
      }
      catch (Exception ex)
      {
        EventLogWriter.LogException(ex);
        return false;
      }
      return true;
    }

    private bool OpenLogFile()
    {
      try
      {
        if (_logfile == null)
        {
          _logfile = File.Open(LogFileName, FileMode.Append, FileAccess.Write, FileShare.None);
          _writer = new BinaryWriter(_logfile);

          if (_logfile != null)
            EventLogWriter.LogMessage(string.Format("Log File ready: {0}", LogFileName), System.Diagnostics.EventLogEntryType.Information);
          else
          {
            EventLogWriter.LogMessage(string.Format("Unable to open logfile: {0}", LogFileName), System.Diagnostics.EventLogEntryType.Error);
            Server.EmergencyShutdown();
          }
        }
      }
      catch (Exception ex)
      {
        EventLogWriter.LogException(ex);
        Server.EmergencyShutdown();
        return false;
      }
      return true;
    }
  }
}
